/*
 *  * Copyright (C) 2021 Huawei Device Co., Ltd.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package com.example.smileyrating;

import com.hsalf.smileyrating.ArgbEvaluator;
import com.hsalf.smileyrating.DisplayAttributes;
import com.hsalf.smileyrating.ValueAnimator;
import com.hsalf.smileyrating.smileys.Bad;
import com.hsalf.smileyrating.smileys.Good;
import com.hsalf.smileyrating.smileys.Great;
import com.hsalf.smileyrating.smileys.Okay;
import com.hsalf.smileyrating.smileys.Terrible;
import com.hsalf.smileyrating.smileys.base.Smiley;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

public class SmileyView extends Component
    implements Component.DrawTask, Component.TouchEventListener, ohos.agp.render.render3d.Component,
    Component.LayoutRefreshedListener {

    private ArgbEvaluator mArgbEvaluator = new ArgbEvaluator();

    private Path mPath = new Path();

    private Smiley mBad = new Bad();

    private Smiley mGood = new Good();

    private Smiley mOkay = new Okay();

    private Smiley mGreat = new Great();

    private Smiley mTerrible = new Terrible();

    private int mCurrentSmileyIndex = 0;

    private Smiley[] mSmileys = new Smiley[] {
        mGreat, mGood, mOkay, mBad, mTerrible
    };

    private Paint mPathPaint = new Paint();

    private Paint mFacePaint = new Paint();

    private ValueAnimator mAnimator = new ValueAnimator();

    public SmileyView(Context context) {
        super(context);
        init();
    }

    public SmileyView(Context context, AttrSet attrs) {
        super(context, attrs);
        init();
    }

    public SmileyView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {

        mAnimator.setFloatValues(0f, 1f);
        mAnimator.setDuration(250);
        mAnimator.setCurveType(AnimatorValue.CurveType.ACCELERATE_DECELERATE);

        mAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                drawSmiley(v);
            }
        });

        mAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                to = null;
                from = null;
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });

        mPathPaint.setAntiAlias(true);
        mPathPaint.setStyle(Paint.Style.FILL_STYLE);

        mFacePaint.setAntiAlias(true);
        mFacePaint.setStyle(Paint.Style.FILL_STYLE);

        drawSmiley(0, mSmileys[0], mSmileys[1]);
        setLayoutRefreshedListener(this::onRefreshed);
        addDrawTask(this::onDraw);
        setTouchEventListener(this::onTouchEvent);

    }

    @Override
    public void postLayout() {
        super.postLayout();
    }

    OnSwipeTouchListener mSwipeListener = new OnSwipeTouchListener(getContext()) {
        @Override
        public void onSwipeLeft() {
            super.onSwipeLeft();
            setSmiley(mCurrentSmileyIndex, mCurrentSmileyIndex + 1);
        }

        @Override
        public void onSwipeRight() {
            super.onSwipeRight();
            setSmiley(mCurrentSmileyIndex, mCurrentSmileyIndex - 1);
        }
    };

    private void setScaleForSmiley() {
        for (int i = 0; i < mSmileys.length; i++) {
            Smiley smiley = mSmileys[i];

            smiley.scale(DisplayAttributes.getWidth(getContext()));
        }
    }

    private Smiley to = null;

    private Smiley from = null;

    private void setSmiley(int from, int to) {

        if (to < 0 || to >= mSmileys.length) {
            return;
        }
        if (mAnimator.isRunning()) {
            return;
        }
        this.to = mSmileys[to];
        this.from = mSmileys[from];
        mCurrentSmileyIndex = to;
        mAnimator.start();

    }

    private void drawSmiley(float fraction) {
        drawSmiley(fraction, from, to);
    }

    private void drawSmiley(float fraction, Smiley from, Smiley to) {

        from.drawFace(to, mPath, fraction);

        mPathPaint.setColor(new Color(from.getDrawingColor()));

        mFacePaint.setColor(
            new Color((Integer) mArgbEvaluator.evaluate(fraction, from.getFaceColor(), to.getFaceColor())));

        invalidate();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.drawCircle(DisplayAttributes.getWidth(getContext()) / 2, DisplayAttributes.getWidth(getContext()) / 2,
            DisplayAttributes.getWidth(getContext()) / 2, mFacePaint);
        canvas.drawPath(mPath, mPathPaint);
    }

    public boolean onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = DisplayAttributes.getWidth(getContext());
        int height = DisplayAttributes.getHeight(getContext());

        if (width < height) {
            setComponentSize(width, width);

            drawSmiley(0, mSmileys[0], mSmileys[1]);
        } else {
            setComponentSize(height, height);

            drawSmiley(0, mSmileys[0], mSmileys[1]);
        }
        setScaleForSmiley();
        return false;
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        return mSwipeListener.onTouchEvent(this, touchEvent);
    }

    @Override
    public void onRefreshed(Component component) {

        onMeasure(getWidth(), getHeight());

    }
}
